package com.atguigu.srb.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.srb.base.exception.Assert;
import com.atguigu.srb.base.result.ResponseEnum;
import com.atguigu.srb.base.utils.JwtUtils;
import com.atguigu.srb.core.enums.TransTypeEnum;
import com.atguigu.srb.core.hfb.FormHelper;
import com.atguigu.srb.core.hfb.HfbConst;
import com.atguigu.srb.core.hfb.RequestHelper;
import com.atguigu.srb.core.pojo.entity.*;
import com.atguigu.srb.core.mapper.LendReturnMapper;
import com.atguigu.srb.core.service.*;
import com.atguigu.srb.core.utils.LendNoUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 还款记录表 服务实现类
 * </p>
 *
 * @author Atguigu
 * @since 2023-01-04
 */
@Service
@Slf4j
public class LendReturnServiceImpl extends ServiceImpl<LendReturnMapper, LendReturn> implements LendReturnService {
        /*
        还款业务：
            1、验证还款计划是否属于当前用户
            2、验证还款计划状态 和时间(判断是否超时)
            构建访问hfb还款接口的自动提交的表单字符串
        还款回调接口：
            3、借款人账户金额扣除
            4、投资人 回款 账户金额增加
            5、更新本期还款计划和回款计划的状态
         */
    @Resource
    UserInfoService userInfoService;
    @Resource
    LendItemReturnService lendItemReturnService;
    @Resource
    LendService lendService;
    @Resource
    LendItemService lendItemService;
    @Resource
    UserAccountService userAccountService;
    @Resource
    TransFlowService transFlowService;
    @Override
    public String borrowReturn(String lendReturnId, String token) {
//        1、验证还款计划是否属于当前用户
        Long userId = JwtUtils.getUserId(token);
        UserInfo userInfo = userInfoService.getById(userId);
        LendReturn lendReturn = this.getById(lendReturnId);
        Assert.assertTrue(userId.longValue()!=lendReturn.getUserId().longValue(),
                ResponseEnum.ERROR);
        Lend lend = lendService.getById(lendReturn.getLendId());
//        2、验证还款计划状态
        Assert.assertTrue(lendReturn.getStatus()!=0 ,ResponseEnum.ERROR );
//        构建访问hfb还款接口的自动提交的表单字符串
        //时间(判断是否超时)
        Map<String, Object> map = new HashMap<>();
        map.put("agentId",HfbConst.AGENT_ID);
        map.put("agentGoodsName","第"+lendReturn.getCurrentPeriod()+"期还款");
        map.put("agentBatchNo",lendReturn.getReturnNo());
        map.put("fromBindCode",userInfo.getBindCode());//还款人id
        long currentTime = System.currentTimeMillis();
        long time = lendReturn.getReturnDate().getTime();
        if(currentTime>time){
            //逾期：计算逾期费用
            long day = (currentTime-time)/(24*60*60*1000) + 1;
            //使用day * 逾期的每天的费用
            lendReturn.setOverdue(true);
            lendReturn.setOverdueTotal(new BigDecimal(1).multiply(new BigDecimal(day)));
        }else{
            lendReturn.setOverdueTotal(new BigDecimal(0));
        }
        map.put("totalAmt",lendReturn.getTotal().add(lendReturn.getOverdueTotal()));
        //hfb处理还款请求时：需要扣除还款人账户金额  转入到投资人账户中
        //查询本期还款计划所有的回款计划 封装到集合中 转为json提交
        List<LendItemReturn> lendItemReturns = lendItemReturnService.list(Wrappers.lambdaQuery(LendItemReturn.class)
                .eq(LendItemReturn::getLendReturnId, lendReturnId));
        List<Map<String ,Object>> lendItemReturnMaps = new ArrayList<>();
        lendItemReturns.forEach(lendItemReturn -> {
            LendItem lendItem = lendItemService.getById(lendItemReturn.getLendItemId());
            UserInfo investUserInfo = userInfoService.getById(lendItemReturn.getInvestUserId());
            Map<String ,Object> lendItemReturnMap = new HashMap<>();
            lendItemReturnMap.put("agentProjectCode",lend.getLendNo());//标的编号
            lendItemReturnMap.put("voteBillNo",lendItem.getLendItemNo());//投资编号
            lendItemReturnMap.put("toBindCode",investUserInfo.getBindCode());//投资人 hfb账户
            //回款总额：  回款总额 - 手续费
            lendItemReturnMap.put("transitAmt",lendItemReturn.getTotal());//回款总额
            lendItemReturnMap.put("baseAmt",lendItemReturn.getPrincipal());//回款本金
            //回款利息： 真实回款利息 - 手续费
            lendItemReturnMap.put("benifitAmt",lendItemReturn.getInterest());//回款利息
            // 计算投资人回报的手续费:
            lendItemReturnMap.put("feeAmt",lendItemReturn.getInterest()
                    .multiply(lend.getServiceRate()));

            lendItemReturnMaps.add(lendItemReturnMap);
        });

        map.put("data", JSON.toJSONString(lendItemReturnMaps));//回款信息
        map.put("voteFeeAmt","0");
        map.put("returnUrl",HfbConst.BORROW_RETURN_RETURN_URL);
        map.put("notifyUrl",HfbConst.BORROW_RETURN_NOTIFY_URL);
        map.put("timestamp",System.currentTimeMillis());
        map.put("sign", RequestHelper.getSign(map));

        //更新还款计划的 逾期数据
        if(lendReturn.getOverdue()){
            this.updateById(lendReturn);//lendReturn 的status仍是未还款
        }

        return FormHelper.buildForm(HfbConst.BORROW_RETURN_URL , map);
    }

    @Override
    public String notifyUrl(HttpServletRequest request) {
        Map<String, Object> map = RequestHelper.switchMap(request.getParameterMap());
        if(!RequestHelper.isSignEquals(map)){
            log.error("还款回调签名验证失败:{}" , JSON.toJSONString(map));
            return "fail";
        }
        if(!"0001".equals(map.get("resultCode").toString())){
            log.error("还款回调业务失败:{}" , JSON.toJSONString(map));
            return "fail";
        }
        //批次号： lendReturn的编号
        // 可以查询到lendReturn
        // 再查询lendReturn的所有的还款计划： 根据每个还款计划 为投资人账户入账
        String agentBatchNo = map.get("agentBatchNo").toString();
        LendReturn lendReturn = this.getOne(Wrappers.lambdaQuery(LendReturn.class)
                .eq(LendReturn::getReturnNo, agentBatchNo));

        Long userId = lendReturn.getUserId();
        //扣除本地 还款人账户金额
        BigDecimal totalAmt = new BigDecimal(map.get("totalAmt").toString());
        UserAccount userAccount = userAccountService.getOne(Wrappers.lambdaQuery(UserAccount.class)
                .eq(UserAccount::getUserId, userId));
        userAccount.setAmount(userAccount.getAmount().subtract(totalAmt));

        userAccountService.updateById(userAccount);

        //保存日志
        UserInfo userInfo = userInfoService.getById(userId);
        //保存还款日志
        TransFlow transFlow = new TransFlow();
        transFlow.setUserId(userId);
        transFlow.setUserName(userInfo.getName());
        transFlow.setTransNo(LendNoUtils.getTransNo());
        transFlow.setTransType(TransTypeEnum.RETURN_DOWN.getTransType());
        transFlow.setTransTypeName(TransTypeEnum.RETURN_DOWN.getTransTypeName());
        transFlow.setTransAmount(totalAmt);
        transFlow.setMemo(TransTypeEnum.RETURN_DOWN.getTransTypeName()+": "+totalAmt.doubleValue()+" 元");
        transFlow.setStatus(1);
        transFlowService.save(transFlow);

        //更新还款计划状态为已还款
        lendReturn.setStatus(1);
        lendReturn.setRealReturnTime(new Date());
        this.updateById(lendReturn);

        //查询还款计划对应的回款计划
        List<LendItemReturn> lendItemReturns = lendItemReturnService.list(Wrappers.lambdaQuery(LendItemReturn.class)
                .eq(LendItemReturn::getLendReturnId, lendReturn.getId()));
        lendItemReturns.forEach(lendItemReturn -> {
            lendItemReturn.setStatus(1);
            lendItemReturn.setRealReturnTime(new Date());
            //投资人账户入账
            UserAccount investUserAccount = userAccountService.getOne(Wrappers.lambdaQuery(UserAccount.class)
                    .eq(UserAccount::getUserId, lendItemReturn.getInvestUserId()));
            UserInfo investUserInfo = userInfoService.getById(lendItemReturn.getInvestUserId());
            investUserAccount.setAmount(investUserAccount.getAmount().add(lendItemReturn.getTotal()));
            userAccountService.updateById(investUserAccount);
            //保存操作日志
            transFlow.setId(null);
            transFlow.setUserId(lendItemReturn.getInvestUserId());
            transFlow.setUserName(investUserInfo.getName());
            transFlow.setTransNo(LendNoUtils.getTransNo());
            transFlow.setTransType(TransTypeEnum.INVEST_BACK.getTransType());
            transFlow.setTransTypeName(TransTypeEnum.INVEST_BACK.getTransTypeName());
            transFlow.setTransAmount(lendItemReturn.getTotal());
            transFlow.setMemo(TransTypeEnum.INVEST_BACK.getTransTypeName()+": "+lendItemReturn.getTotal().doubleValue()+" 元");
            transFlow.setStatus(1);
            transFlowService.save(transFlow);
        });
        lendItemReturnService.updateBatchById(lendItemReturns);

        return "success";
    }
}
